import matplotlib
matplotlib.use('Agg')  # 使用非交互式后端，避免GUI相关错误

import os
import sys
import base64
import io
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
from flask import Flask, render_template, request, jsonify
from newuser_rec import novice_stable_recommendation
from stock_to_stock import SimilarStockRecommender
from stock_in_industry import IndustryStockRecommender
from industry_to_industry import IndustryExpansionRecommender
from simple_chart import create_simple_chart, create_chart_svg

app = Flask(__name__)

# 全局推荐器实例
stock_recommender = None
industry_recommender = None
expansion_recommender = None

def get_chinese_font():
    """检测并返回可用的中文字体"""
    candidate_fonts = [
        "SimHei", "Microsoft YaHei", "PingFang SC", 
        "Heiti SC", "WenQuanYi Zen Hei"
    ]
    
    available_fonts = set(f.name for f in font_manager.fontManager.ttflist)
    for font in candidate_fonts:
        if font in available_fonts:
            return font
    
    return "DejaVu Sans"  # 兜底字体

def create_visualization_chart(data, chart_type, title):
    """创建可视化图表 - 全新简化版本"""
    try:
        # 设置中文字体
        plt.rcParams['font.sans-serif'] = [get_chinese_font()]
        plt.rcParams['axes.unicode_minus'] = False
        
        if not data or not isinstance(data, list):
            print(f"图表数据无效: {type(data)}")
            return None
            
        # 提取数据
        labels = []
        values = []
        
        for item in data:
            if not isinstance(item, dict):
                continue
                
            # 提取标签
            label = None
            if '股票名称' in item:
                label = item['股票名称']
            elif '行业名称' in item:
                label = item['行业名称']
            else:
                # 找第一个非空字符串作为标签
                for key, value in item.items():
                    if isinstance(value, str) and value.strip():
                        label = value[:6]  # 限制长度
                        break
            
            # 提取数值
            value = None
            if '联动系数' in item:
                value = float(item['联动系数'])
            elif '综合评分' in item:
                value = float(item['综合评分'])
            elif '平均成交额（亿元）' in item:
                value = float(item['平均成交额（亿元）'])
            elif '相关度分数' in item:
                value = float(item['相关度分数'])
            else:
                # 找第一个数值作为值
                for key, val in item.items():
                    if isinstance(val, (int, float)) and not pd.isna(val):
                        value = float(val)
                        break
            
            if label and value is not None:
                labels.append(label)
                values.append(value)
        
        if len(labels) < 2 or len(values) < 2:
            print(f"数据不足: labels={len(labels)}, values={len(values)}")
            return None
        
        # 创建极简图表
        plt.figure(figsize=(6, 4))
        plt.bar(range(len(values)), values, color='lightblue')
        plt.title(title, fontsize=12)
        plt.xlabel('项目')
        plt.ylabel('数值')
        
        # 设置x轴标签
        plt.xticks(range(len(labels)), labels, rotation=45, ha='right')
        
        # 添加数值标签
        for i, v in enumerate(values):
            plt.text(i, v + max(values)*0.01, f'{v:.2f}', ha='center', va='bottom')
        
        # 保存图表
        buffer = io.BytesIO()
        plt.savefig(buffer, format='png', dpi=50, bbox_inches='tight', 
                   facecolor='white', edgecolor='none')
        buffer.seek(0)
        image_data = buffer.getvalue()
        buffer.close()
        plt.close()
        
        # 返回base64编码
        return base64.b64encode(image_data).decode()
        
    except Exception as e:
        print(f"创建图表失败: {e}")
        import traceback
        traceback.print_exc()
        return None

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/novice')
def novice():
    return render_template('novice.html')

@app.route('/expert')
def expert():
    return render_template('expert.html')

@app.route('/api/novice_recommend', methods=['POST'])
def api_novice_recommend():
    try:
        # 使用函数而不是类
        stock_attr_path = "hs300_data/graph_stock_nodes.csv"
        result = novice_stable_recommendation(
            stock_attr_path=stock_attr_path,
            top_n=5,
            vol_threshold=4.87,
            turnover_min=7.22,
            max_per_industry=1
        )
        
        if isinstance(result, str):
            return jsonify({'success': False, 'error': result})
        
        # 格式化推荐结果
        recommendations = []
        for _, row in result.iterrows():
            recommendations.append({
                '股票代码': str(row['股票代码']),
                '股票名称': str(row['股票名称']),
                '所属行业': str(row['所属行业']),
                '波动率': round(float(row['波动率']), 4),
                '平均成交额（亿元）': round(float(row['平均成交额（亿元）']), 2)
            })
        
        # 创建可视化图表
        print(f"新手推荐数据: {recommendations}")
        chart_data = create_chart_svg(recommendations, '新手推荐股票平均成交额')
        print(f"图表数据生成: {'成功' if chart_data else '失败'}")
        
        return jsonify({
            'success': True,
            'data': recommendations,
            'message': f'为您推荐了{len(recommendations)}只稳健型股票',
            'chart': chart_data
        })
        
    except Exception as e:
        print(f"新手推荐API错误: {e}")
        return jsonify({'success': False, 'error': f'推荐失败: {str(e)}'})

@app.route('/api/get_reference_stocks', methods=['GET'])
def api_get_reference_stocks():
    try:
        # 返回一些示例股票作为参考
        sample_stocks = [
            {'股票代码': 'sz.002230', '股票名称': '科大讯飞', '所属行业': 'I65软件和信息技术服务业'},
            {'股票代码': 'sh.600519', '股票名称': '贵州茅台', '所属行业': 'C15酒、饮料和精制茶制造业'},
            {'股票代码': 'sz.000001', '股票名称': '平安银行', '所属行业': 'J66货币金融服务'},
            {'股票代码': 'sh.601318', '股票名称': '中国平安', '所属行业': 'J68保险业'},
            {'股票代码': 'sz.000002', '股票名称': '万科A', '所属行业': 'K70房地产业'},
            {'股票代码': 'sh.600036', '股票名称': '招商银行', '所属行业': 'J66货币金融服务'},
            {'股票代码': 'sz.000858', '股票名称': '五粮液', '所属行业': 'C15酒、饮料和精制茶制造业'},
            {'股票代码': 'sh.600276', '股票名称': '恒瑞医药', '所属行业': 'C27医药制造业'}
        ]
        
        return jsonify({
            'success': True,
            'data': sample_stocks
        })
        
    except Exception as e:
        print(f"获取参考股票API错误: {e}")
        return jsonify({'success': False, 'error': f'获取失败: {str(e)}'})

@app.route('/api/stock_to_stock', methods=['POST'])
def api_stock_to_stock():
    try:
        if not stock_recommender:
            return jsonify({'success': False, 'error': '推荐器未初始化'})
        
        data = request.get_json()
        input_stock = data.get('input_stock', '').strip()
        top_n = data.get('top_n', 5)
        
        if not input_stock:
            return jsonify({'success': False, 'error': '请输入股票代码或名称'})
        
        # 先尝试通过股票名称查找股票代码
        stock_code = input_stock
        if not stock_recommender.G.nodes.get(input_stock):
            # 如果输入的不是股票代码，尝试通过名称查找
            stock_code = stock_recommender._get_stock_code_by_name(input_stock)
            if not stock_code:
                return jsonify({'success': False, 'error': f'未找到股票：{input_stock}，请检查股票代码或名称'})
        
        result = stock_recommender.recommend_similar(stock_code, top_n)
        
        # 检查是否有错误
        if isinstance(result, list) and len(result) > 0 and 'error' in result[0]:
            return jsonify({'success': False, 'error': result[0]['error']})
        
        # 格式化推荐结果
        formatted_result = []
        for item in result:
            formatted_result.append({
                '股票代码': str(item['股票代码']),
                '股票名称': str(item['股票名称']),
                '所属行业': str(item['所属行业']),
                '联动系数': round(float(item['与输入股票的联动系数']), 4)
            })
        
        # 创建可视化图表
        print(f"知股荐股数据: {formatted_result}")
        chart_data = create_chart_svg(formatted_result, f'与{input_stock}的联动系数')
        print(f"知股荐股图表生成: {'成功' if chart_data else '失败'}")
        
        return jsonify({
            'success': True,
            'data': formatted_result,
            'message': f'为您推荐了{len(formatted_result)}只与{input_stock}联动性强的股票',
            'chart': chart_data
        })
        
    except Exception as e:
        print(f"知股荐股API错误: {e}")
        return jsonify({'success': False, 'error': f'推荐失败: {str(e)}'})

@app.route('/api/get_industries', methods=['GET'])
def api_get_industries():
    try:
        if not industry_recommender:
            return jsonify({'success': False, 'error': '推荐器未初始化'})
        
        industries = industry_recommender.industries
        return jsonify({
            'success': True,
            'data': industries
        })
        
    except Exception as e:
        print(f"获取行业列表API错误: {e}")
        return jsonify({'success': False, 'error': f'获取失败: {str(e)}'})

@app.route('/api/industry_stock', methods=['POST'])
def api_industry_stock():
    try:
        if not industry_recommender:
            return jsonify({'success': False, 'error': '推荐器未初始化'})
        
        data = request.get_json()
        input_industry = data.get('input_industry', '').strip()
        top_n = data.get('top_n', 5)
        
        if not input_industry:
            return jsonify({'success': False, 'error': '请选择行业'})
        
        # 行业名称校验
        if input_industry not in industry_recommender.industries:
            return jsonify({'success': False, 'error': f'未找到行业「{input_industry}」'})
        
        # 筛选行业内股票并计算评分
        industry_stocks = industry_recommender.stock_df[industry_recommender.stock_df["industry"] == input_industry].copy()
        total_stocks = len(industry_stocks)
        if total_stocks == 0:
            return jsonify({'success': False, 'error': f'行业「{input_industry}」下无股票数据'})
        
        # 用「成交额/波动率」作为综合评分（值越高越推荐）
        industry_stocks["score"] = industry_stocks["avg_turnover_billion"] / (industry_stocks["volatility"] + 1e-8)
        sorted_stocks = industry_stocks.sort_values(by="score", ascending=False)
        display_stocks = sorted_stocks.head(top_n)
        
        # 格式化推荐结果
        formatted_result = []
        for idx, (_, row) in enumerate(display_stocks.iterrows(), 1):
            stock_code = row["stock_code"]
            stock_name = industry_recommender.stock_name_map.get(stock_code, "【名称未获取到】")
            formatted_result.append({
                '股票代码': str(stock_code),
                '股票名称': str(stock_name),
                '所属行业': str(input_industry),
                '综合评分': round(float(row['score']), 4),
                '平均成交额（亿元）': round(float(row['avg_turnover_billion']), 2),
                '波动率': round(float(row['volatility']), 4)
            })
        
        # 创建可视化图表
        print(f"行业荐股数据: {formatted_result}")
        chart_data = create_chart_svg(formatted_result, f'{input_industry}股票综合评分')
        print(f"行业荐股图表生成: {'成功' if chart_data else '失败'}")
        
        return jsonify({
            'success': True,
            'data': formatted_result,
            'message': f'为您推荐了{len(formatted_result)}只{input_industry}的优质股票',
            'chart': chart_data
        })
        
    except Exception as e:
        print(f"行业荐股API错误: {e}")
        return jsonify({'success': False, 'error': f'推荐失败: {str(e)}'})

@app.route('/api/industry_expansion', methods=['POST'])
def api_industry_expansion():
    try:
        if not expansion_recommender:
            return jsonify({'success': False, 'error': '推荐器未初始化'})
        
        data = request.get_json()
        input_industry = data.get('input_industry', '').strip()
        top_n = data.get('top_n', 5)
        expansion_type = data.get('type', 'related')
        
        if not input_industry:
            return jsonify({'success': False, 'error': '请选择行业'})
        
        result = expansion_recommender.recommend_expansion(input_industry, top_n)
        
        if 'error' in result:
            return jsonify({'success': False, 'error': result['error']})
        
        # 根据类型选择推荐结果
        if expansion_type == 'related':
            recommendations = result['related']
            message = f'为您推荐了{len(recommendations)}个与{input_industry}相关的行业'
        else:  # hedge
            recommendations = result['hedge']
            message = f'为您推荐了{len(recommendations)}个与{input_industry}对冲的行业'
        
        # 格式化推荐结果，确保相关度分数不为空
        formatted_result = []
        seen_industries = set()  # 用于去重
        
        for item in recommendations:
            # 如果已经达到要求的数量，停止添加
            if len(formatted_result) >= top_n:
                break
                
            # 获取原始相关度分数
            correlation = item.get('correlation', 0)
            industry_name = str(item['industry'])
            
            # 检查是否已经添加过这个行业
            if industry_name in seen_industries:
                print(f"⚠️  发现重复行业: {industry_name}，跳过")
                continue
            
            # 更严格的空值检查
            if (correlation is None or 
                correlation == '' or 
                str(correlation).strip() == '' or
                str(correlation).lower() == 'nan' or
                str(correlation).lower() == 'none' or
                str(correlation).lower() == 'null'):
                correlation = 0.0
            
            try:
                correlation_float = float(correlation)
                # 检查是否为NaN或无穷大
                if pd.isna(correlation_float) or (correlation_float != correlation_float) or abs(correlation_float) > 1e10:
                    correlation_float = 0.0
            except (ValueError, TypeError):
                correlation_float = 0.0
            
            # 对于对冲行业，如果相关度为0，这可能是数据问题，我们需要跳过这个行业
            if correlation_float == 0.0 and expansion_type == 'hedge':
                print(f"⚠️  发现相关度为0的对冲行业: {industry_name}，跳过")
                continue
            
            formatted_result.append({
                '行业名称': industry_name,
                '相关度分数': round(correlation_float, 4)
            })
            seen_industries.add(industry_name)
        
        # 如果结果数量不足，尝试从原始推荐中获取更多
        if len(formatted_result) < top_n:
            print(f"⚠️  当前只有{len(formatted_result)}个有效行业，尝试获取更多...")
            # 从原始推荐中查找更多有效的行业
            for item in recommendations:
                if len(formatted_result) >= top_n:
                    break
                    
                correlation = item.get('correlation', 0)
                industry_name = str(item['industry'])
                
                # 跳过已经添加的行业
                if industry_name in seen_industries:
                    continue
                
                # 处理相关度
                try:
                    correlation_float = float(correlation)
                    if pd.isna(correlation_float) or (correlation_float != correlation_float) or abs(correlation_float) > 1e10:
                        correlation_float = 0.0
                except (ValueError, TypeError):
                    correlation_float = 0.0
                
                # 对于对冲行业，即使是0.0也接受（因为我们需要达到指定数量）
                if expansion_type == 'hedge' and correlation_float == 0.0:
                    print(f"⚠️  接受相关度为0的对冲行业: {industry_name}（为了达到数量要求）")
                
                formatted_result.append({
                    '行业名称': industry_name,
                    '相关度分数': round(correlation_float, 4)
                })
                seen_industries.add(industry_name)
        
        # 创建可视化图表
        print(f"行业拓展数据: {formatted_result}")
        chart_title = f'{input_industry}的{"相关" if expansion_type == "related" else "对冲"}行业'
        chart_data = create_chart_svg(formatted_result, chart_title)
        print(f"行业拓展图表生成: {'成功' if chart_data else '失败'}")
        
        return jsonify({
            'success': True,
            'data': formatted_result,
            'message': message,
            'chart': chart_data
        })
        
    except Exception as e:
        print(f"行业拓展API错误: {e}")
        return jsonify({'success': False, 'error': f'推荐失败: {str(e)}'})

def initialize_recommenders():
    """初始化所有推荐器"""
    global stock_recommender, industry_recommender, expansion_recommender
    
    try:
        print("正在初始化推荐器...")
        
        # 检查数据文件是否存在
        required_files = [
            "hs300_data/hs300_daily_clean.csv",
            "hs300_data/hs300_industry_clean.csv",
            "hs300_data/graph_stock_nodes.csv",
            "hs300_data/graph_stock_links.csv",
            "hs300_data/industry_correlation.csv"
        ]
        
        missing_files = []
        for file_path in required_files:
            if not os.path.exists(file_path):
                missing_files.append(file_path)
        
        if missing_files:
            print(f"❌ 缺少必要的数据文件: {missing_files}")
            return False
        
        # 初始化推荐器
        stock_recommender = SimilarStockRecommender()
        industry_recommender = IndustryStockRecommender()
        expansion_recommender = IndustryExpansionRecommender()
        
        print("推荐器初始化完成！")
        return True
        
    except Exception as e:
        print(f"❌ 系统初始化失败，请检查数据文件")
        print(f"错误详情: {e}")
        return False

if __name__ == '__main__':
    if initialize_recommenders():
        print("✅ 股票推荐系统启动成功！")
        print("🌐 访问地址: http://localhost:5000")
        app.run(host='0.0.0.0', port=5000, debug=False)
    else:
        print("❌ 系统初始化失败，请检查数据文件")
        sys.exit(1)
